﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace pbvs.Calculations
{
    public class CommutationTable
    {
        public enum Gender{
            Male,
            Female
        }

        public enum Rate
        {
            First20,
            Thereafter
        }

        public enum Calculation
        {
            Scale2022,
            Ax
        }

        private readonly IList<CommutationTable> _ctVars;
        private readonly Gender _gender;
        public int Age { get; set; }
        public decimal Male1994UP { get; set; }
        public decimal MaleAaScale { get; set; }
        public decimal Female1994UP { get; set; }
        public decimal FemaleAaScale { get; set; }
        public decimal Male2022 { get; set; }
        public decimal Female2022 { get; set; }
        public decimal MaleFirst20Dx { get; set; }
        public decimal MaleThereafterDx { get; set; }
        public decimal MaleFirst20Nx { get; set; }
        public decimal MaleThereafterNx { get; set; }
        public decimal FemaleFirst20Dx { get; set; }
        public decimal FemaleThereafterDx { get; set; }
        public decimal FemaleFirst20Nx { get; set; }
        public decimal FemaleThereafterNx { get; set; }
        public decimal MaleQx { get; set; }
        public decimal FemaleQx { get; set; }
	    public decimal Cola { get; set; }

	    public CommutationTable() { }

        public CommutationTable(int age, Gender gender, IList<CommutationTable> ctVars, decimal cola)
        {
	        this._ctVars = ctVars;
            this._gender = gender;
            CommutationTable ct = _ctVars.First(t => t.Age == age);
            this.Age = age;
            this.Male1994UP = ct.Male1994UP;
            this.MaleAaScale = ct.MaleAaScale;
            this.Male2022 = ct.Male2022;
            this.MaleFirst20Dx = ct.MaleFirst20Dx;
            this.MaleThereafterDx = ct.MaleThereafterDx;
            this.Female1994UP = ct.Female1994UP;
            this.FemaleAaScale = ct.FemaleAaScale;
            this.Female2022 = ct.Female2022;
            this.FemaleFirst20Dx = ct.FemaleFirst20Dx;
            this.FemaleThereafterDx = ct.FemaleThereafterDx;
			this.Cola = cola;
            
            CalculateNxVariables();
            CalculateQxVariables();
        }

        public void CalculateNxVariables()
        {
            if (this._gender == Gender.Male)
            {
                this.MaleFirst20Nx = _ctVars.Where(t => t.Age >= this.Age).Sum(t => t.MaleFirst20Dx);
                this.MaleThereafterNx = _ctVars.Where(t => t.Age >= this.Age).Sum(t => t.MaleThereafterDx);
            }
            else
            {
                this.FemaleFirst20Nx = _ctVars.Where(t => t.Age >= this.Age).Sum(t => t.FemaleFirst20Dx);
                this.FemaleThereafterNx = _ctVars.Where(t => t.Age >= this.Age).Sum(t => t.FemaleThereafterDx);
            }
        }

        public decimal CalculateAxVariables(bool useFirst20)
        {
            double dx;
            double nx;
            if (this._gender == Gender.Male)
            {
                dx = Convert.ToDouble(useFirst20 ? MaleFirst20Dx : MaleThereafterDx);
                nx = Convert.ToDouble(useFirst20 ? MaleFirst20Nx : MaleThereafterNx);
            }
            else
            {
                dx = Convert.ToDouble(useFirst20 ? FemaleFirst20Dx : FemaleThereafterDx);
                nx = Convert.ToDouble(useFirst20 ? FemaleFirst20Nx : FemaleThereafterNx);
            }
            double nxDivDx = (nx / dx);
            double a = 12 - 1;
            double b = 2;
            double c = 12;
            double yearsDivide = ((a) / b / c);
            double cola = (1 + Convert.ToDouble(this.Cola));
            double exponent = (-(a) / b / c);
            double ax = (nxDivDx - yearsDivide) * Math.Pow(cola, exponent);
            return Convert.ToDecimal(ax);
        }

        public void CalculateQxVariables()
        {
            if (this._gender == Gender.Male)
            {
                if (this.Age < 120)
                {
                    this.MaleQx = 1 - (_ctVars.First(t => t.Age == this.Age + 1).Male1994UP / this.Male1994UP);
                }
            }
            else
            {
                if (this.Age < 120)
                {
                    this.FemaleQx = 1 - (_ctVars.First(t => t.Age == this.Age + 1).Female2022 / this.Female2022);
                }
            }
        }

        public decimal GetVariable(Rate rate, Calculation calc)
        {
            decimal ret = this._gender == Gender.Male ? Male2022 : Female2022;
            if (calc == Calculation.Ax)
            {
                ret = rate == Rate.First20 ? CalculateAxVariables(true) : CalculateAxVariables(false);
            }
            return ret;
        }
    }
}